#include "bsp.h"
#include <string.h>
#include "app_common.h"

SPI_HandleTypeDef SPI1_Handler,SPI5_Handler;  //SPI句柄

void USR_GPIO_Config(void)
{
	GPIO_InitTypeDef GPIO_InitStruct;

	__HAL_RCC_GPIOA_CLK_ENABLE();
	__HAL_RCC_GPIOB_CLK_ENABLE();
	__HAL_RCC_GPIOD_CLK_ENABLE();
	__HAL_RCC_GPIOF_CLK_ENABLE();
	__HAL_RCC_GPIOH_CLK_ENABLE();
	__HAL_RCC_GPIOG_CLK_ENABLE();
	__HAL_RCC_GPIOI_CLK_ENABLE();

	GPIO_InitStruct.Pin = GPIO_PIN_4;
	GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;
	GPIO_InitStruct.Pull = GPIO_NOPULL;
	GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_MEDIUM;
	HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);

	GPIO_InitStruct.Pin = GPIO_PIN_15;
	GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;
	GPIO_InitStruct.Pull = GPIO_NOPULL;
	GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_MEDIUM;
	HAL_GPIO_Init(GPIOB, &GPIO_InitStruct);
	HAL_GPIO_WritePin(GPIOB, GPIO_PIN_15,0);

	GPIO_InitStruct.Pin = GPIO_PIN_11|GPIO_PIN_12|GPIO_PIN_13;
	GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;
	GPIO_InitStruct.Pull = GPIO_NOPULL;
	GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_MEDIUM;
	HAL_GPIO_Init(GPIOD, &GPIO_InitStruct);
	HAL_GPIO_WritePin(GPIOD, GPIO_PIN_11|GPIO_PIN_12|GPIO_PIN_13,1);

	GPIO_InitStruct.Pin = GPIO_PIN_2|GPIO_PIN_7;
	GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;
	GPIO_InitStruct.Pull = GPIO_NOPULL;
	GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_MEDIUM;
	HAL_GPIO_Init(GPIOG, &GPIO_InitStruct);
	HAL_GPIO_WritePin(GPIOG, GPIO_PIN_2,1);

	GPIO_InitStruct.Pin = GPIO_PIN_12|GPIO_PIN_2;
	GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;
	GPIO_InitStruct.Pull = GPIO_NOPULL;
	GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_MEDIUM;
	HAL_GPIO_Init(GPIOH, &GPIO_InitStruct);
	HAL_GPIO_WritePin(GPIOH, GPIO_PIN_12,0);

	GPIO_InitStruct.Pin = GPIO_PIN_10;
	GPIO_InitStruct.Mode = GPIO_MODE_INPUT;
	GPIO_InitStruct.Pull = GPIO_NOPULL;
	GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_MEDIUM;
	HAL_GPIO_Init(GPIOF, &GPIO_InitStruct);

	HAL_GPIO_WritePin(GPIOI, GPIO_PIN_1,1);	//解决初始化低电平脉冲问题
	GPIO_InitStruct.Pin = GPIO_PIN_1;
	GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;
	GPIO_InitStruct.Pull = GPIO_NOPULL;
	GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW;
	HAL_GPIO_Init(GPIOI, &GPIO_InitStruct);
	HAL_GPIO_WritePin(GPIOI, GPIO_PIN_1,1);

	HAL_GPIO_WritePin(GPIOG, GPIO_PIN_10,1);	//解决初始化低电平脉冲问题
	GPIO_InitStruct.Pin = GPIO_PIN_10;
	GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;
	GPIO_InitStruct.Pull = GPIO_NOPULL;
	GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW;
	HAL_GPIO_Init(GPIOG, &GPIO_InitStruct);
	HAL_GPIO_WritePin(GPIOG, GPIO_PIN_1,1);
}
//TIM3 PWM部分初始化
//PWM输出初始化
//arr：自动重装值
//psc：时钟预分频数
void USR_PWM_Config(uint16_t arr,uint16_t psc)
{
	GPIO_InitTypeDef 		GPIO_InitStruct;
	TIM_HandleTypeDef 		TIM3_Handler;         //定时器3PWM句柄
	TIM_OC_InitTypeDef 		TIM3_CH2Handler,TIM3_CH3Handler,TIM3_CH4Handler; //定时器3通道2,3,4句柄

	__HAL_RCC_GPIOC_CLK_ENABLE();
	__HAL_RCC_TIM3_CLK_ENABLE();			//使能定时器3

	GPIO_InitStruct.Pin = GPIO_PIN_7|GPIO_PIN_8|GPIO_PIN_9;
	GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
	GPIO_InitStruct.Pull = GPIO_NOPULL;
	GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_VERY_HIGH;
	GPIO_InitStruct.Alternate= GPIO_AF2_TIM3;
	HAL_GPIO_Init(GPIOC, &GPIO_InitStruct);

	/* 初始化TIM3 */
	TIM3_Handler.Instance=TIM3;            //定时器3
	TIM3_Handler.Init.Prescaler=psc;       //定时器分频
	TIM3_Handler.Init.CounterMode=TIM_COUNTERMODE_UP;//向上计数模式
	TIM3_Handler.Init.Period=arr;          //自动重装载值
	TIM3_Handler.Init.ClockDivision=TIM_CLOCKDIVISION_DIV1;
	HAL_TIM_PWM_Init(&TIM3_Handler);       //初始化PWM

	TIM3_CH2Handler.OCMode=TIM_OCMODE_PWM1; //模式选择PWM1
	TIM3_CH2Handler.Pulse=0;            //设置比较值,此值用来确定占空比
	TIM3_CH2Handler.OCPolarity=TIM_OCPOLARITY_HIGH; //输出比较极性为低
	HAL_TIM_PWM_ConfigChannel(&TIM3_Handler,&TIM3_CH2Handler,TIM_CHANNEL_2);//配置TIM3通道2
	HAL_TIM_PWM_Start(&TIM3_Handler,TIM_CHANNEL_2);//开启PWM通道2

	TIM3_CH3Handler.OCMode=TIM_OCMODE_PWM1; //模式选择PWM1
	TIM3_CH3Handler.Pulse=0;            //设置比较值,此值用来确定占空比
	TIM3_CH3Handler.OCPolarity=TIM_OCPOLARITY_HIGH; //输出比较极性为低
	HAL_TIM_PWM_ConfigChannel(&TIM3_Handler,&TIM3_CH3Handler,TIM_CHANNEL_3);//配置TIM3通道3
	HAL_TIM_PWM_Start(&TIM3_Handler,TIM_CHANNEL_3);//开启PWM通道3

	TIM3_CH4Handler.OCMode=TIM_OCMODE_PWM1; //模式选择PWM1
	TIM3_CH4Handler.Pulse=0;            //设置比较值,此值用来确定占空比，默认比较值为自动重装载值的一半,即占空比为50%
	TIM3_CH4Handler.OCPolarity=TIM_OCPOLARITY_HIGH; //输出比较极性为低
	HAL_TIM_PWM_ConfigChannel(&TIM3_Handler,&TIM3_CH4Handler,TIM_CHANNEL_4);//配置TIM3通道4
	HAL_TIM_PWM_Start(&TIM3_Handler,TIM_CHANNEL_4);//开启PWM通道4
}
//设置TIM通道占空比
//compare:比较值
void TIM_SetTIM3Compare4(uint8_t channel,uint8_t duty)
{
	switch(channel)
	{
		case 0x02:
			TIM3->CCR2=duty*100;
		break;
		case 0x03:
			TIM3->CCR3=duty*100;
		break;
		case 0x04:
			TIM3->CCR4=duty*100;
		break;
		default:
		break;
	}
}

void MOTOR_CTL(uint8_t dir,uint8_t duty)
{
	if(dir)
		MOTOR_DIR_UP;
	else
		MOTOR_DIR_DOWN;
	TIM_SetTIM3Compare4(2,duty);
}

//以下是SPI模块的初始化代码，配置成主机模式
//SPI口初始化
//这里针是对SPI1,SPI5的初始化
void USR_SPI_Init(void)
{
	GPIO_InitTypeDef GPIO_Initure;

	__HAL_RCC_GPIOA_CLK_ENABLE();
	__HAL_RCC_GPIOB_CLK_ENABLE();
	__HAL_RCC_GPIOF_CLK_ENABLE();       //使能GPIOF时钟
	__HAL_RCC_SPI1_CLK_ENABLE();
	__HAL_RCC_SPI5_CLK_ENABLE();        //使能SPI5时钟

	//PA5,6
	GPIO_Initure.Pin=GPIO_PIN_5|GPIO_PIN_6;
	GPIO_Initure.Mode=GPIO_MODE_AF_PP;              //复用推挽输出
	GPIO_Initure.Pull=GPIO_NOPULL;                  //上拉
	GPIO_Initure.Speed=GPIO_SPEED_FAST;             //快速
	GPIO_Initure.Alternate=GPIO_AF5_SPI1;           //复用为SPI1
	HAL_GPIO_Init(GPIOA,&GPIO_Initure);
	//PB5
	GPIO_Initure.Pin=GPIO_PIN_5;
	GPIO_Initure.Mode=GPIO_MODE_AF_PP;              //复用推挽输出
	GPIO_Initure.Pull=GPIO_NOPULL;                  //上拉
	GPIO_Initure.Speed=GPIO_SPEED_FAST;             //快速
	GPIO_Initure.Alternate=GPIO_AF5_SPI1;           //复用为SPI1
	HAL_GPIO_Init(GPIOB,&GPIO_Initure);
	//PF7,8,9
	GPIO_Initure.Pin=GPIO_PIN_7|GPIO_PIN_8|GPIO_PIN_9;
	GPIO_Initure.Mode=GPIO_MODE_AF_PP;              //复用推挽输出
	GPIO_Initure.Pull=GPIO_NOPULL;                  //上拉
	GPIO_Initure.Speed=GPIO_SPEED_FAST;             //快速
	GPIO_Initure.Alternate=GPIO_AF5_SPI5;           //复用为SPI5
	HAL_GPIO_Init(GPIOF,&GPIO_Initure);

	SPI1_Handler.Instance=SPI1;                         //SP1
	SPI1_Handler.Init.Mode=SPI_MODE_MASTER;             //设置SPI工作模式，设置为主模式
	SPI1_Handler.Init.Direction=SPI_DIRECTION_2LINES;   //设置SPI单向或者双向的数据模式:SPI设置为双线模式
	SPI1_Handler.Init.DataSize=SPI_DATASIZE_8BIT;       //设置SPI的数据大小:SPI发送接收8位帧结构
	SPI1_Handler.Init.CLKPolarity=SPI_POLARITY_HIGH;    //串行同步时钟的空闲状态为高电平
	SPI1_Handler.Init.CLKPhase=SPI_PHASE_2EDGE;         //串行同步时钟的第二个跳变沿（上升或下降）数据被采样
	SPI1_Handler.Init.NSS=SPI_NSS_SOFT;                 //NSS信号由硬件（NSS管脚）还是软件（使用SSI位）管理:内部NSS信号有SSI位控制
	SPI1_Handler.Init.BaudRatePrescaler=SPI_BAUDRATEPRESCALER_256;//定义波特率预分频的值:波特率预分频值为256
	SPI1_Handler.Init.FirstBit=SPI_FIRSTBIT_MSB;        //指定数据传输从MSB位还是LSB位开始:数据传输从MSB位开始
	SPI1_Handler.Init.TIMode=SPI_TIMODE_DISABLE;        //关闭TI模式
	SPI1_Handler.Init.CRCCalculation=SPI_CRCCALCULATION_DISABLE;//关闭硬件CRC校验
	SPI1_Handler.Init.CRCPolynomial=7;                  //CRC值计算的多项式
	HAL_SPI_Init(&SPI1_Handler);//初始化
	__HAL_SPI_ENABLE(&SPI1_Handler);                    //使能SPI1
	//USR_SPI_ReadWriteByte(USR_SPI1,0Xff);               //启动传输

    SPI5_Handler.Instance=SPI5;                         //SP5
    SPI5_Handler.Init.Mode=SPI_MODE_MASTER;             //设置SPI工作模式，设置为主模式
    SPI5_Handler.Init.Direction=SPI_DIRECTION_2LINES;   //设置SPI单向或者双向的数据模式:SPI设置为双线模式
    SPI5_Handler.Init.DataSize=SPI_DATASIZE_8BIT;       //设置SPI的数据大小:SPI发送接收8位帧结构
    SPI5_Handler.Init.CLKPolarity=SPI_POLARITY_HIGH;    //串行同步时钟的空闲状态为高电平
    SPI5_Handler.Init.CLKPhase=SPI_PHASE_2EDGE;         //串行同步时钟的第二个跳变沿（上升或下降）数据被采样
    SPI5_Handler.Init.NSS=SPI_NSS_SOFT;                 //NSS信号由硬件（NSS管脚）还是软件（使用SSI位）管理:内部NSS信号有SSI位控制
    SPI5_Handler.Init.BaudRatePrescaler=SPI_BAUDRATEPRESCALER_256;//定义波特率预分频的值:波特率预分频值为256
    SPI5_Handler.Init.FirstBit=SPI_FIRSTBIT_MSB;        //指定数据传输从MSB位还是LSB位开始:数据传输从MSB位开始
    SPI5_Handler.Init.TIMode=SPI_TIMODE_DISABLE;        //关闭TI模式
    SPI5_Handler.Init.CRCCalculation=SPI_CRCCALCULATION_DISABLE;//关闭硬件CRC校验
    SPI5_Handler.Init.CRCPolynomial=7;                  //CRC值计算的多项式
    HAL_SPI_Init(&SPI5_Handler);//初始化

    __HAL_SPI_ENABLE(&SPI5_Handler);                    //使能SPI5
    //USR_SPI_ReadWriteByte(USR_SPI5,0Xff);               //启动传输
}

//SPI速度设置函数
//SPI速度=fAPB1/分频系数
//@ref SPI_BaudRate_Prescaler:SPI_BAUDRATEPRESCALER_2~SPI_BAUDRATEPRESCALER_2 256
//fAPB1时钟一般为45Mhz：
void USR_SPI_SetSpeed(SPI_PORT_E ucPORT,uint8_t SPI_BaudRatePrescaler)
{
    assert_param(IS_SPI_BAUDRATE_PRESCALER(SPI_BaudRatePrescaler));//判断有效性
    if(ucPORT == USR_SPI1)
    {
    	__HAL_SPI_DISABLE(&SPI1_Handler);            //关闭SPI
    	SPI1_Handler.Instance->CR1&=0XFFC7;          //位3-5清零，用来设置波特率
    	SPI1_Handler.Instance->CR1|=SPI_BaudRatePrescaler;//设置SPI速度
    	__HAL_SPI_ENABLE(&SPI1_Handler);             //使能SPI
    }
    else if(ucPORT == USR_SPI5)
    {
		__HAL_SPI_DISABLE(&SPI5_Handler);            //关闭SPI
		SPI5_Handler.Instance->CR1&=0XFFC7;          //位3-5清零，用来设置波特率
		SPI5_Handler.Instance->CR1|=SPI_BaudRatePrescaler;//设置SPI速度
		__HAL_SPI_ENABLE(&SPI5_Handler);             //使能SPI
    }
}
//SPI 读写一个字节
//TxData:要写入的字节
//返回值:读取到的字节
uint8_t USR_SPI_ReadWriteByte(SPI_PORT_E ucPORT,uint8_t TxData)
{
	uint8_t Rxdata;
	if(ucPORT == USR_SPI1)
		HAL_SPI_TransmitReceive(&SPI1_Handler,&TxData,&Rxdata,1, 1000);
	else if(ucPORT == USR_SPI5)
		HAL_SPI_TransmitReceive(&SPI5_Handler,&TxData,&Rxdata,1, 1000);
 	return Rxdata;          		    //返回收到的数据
}
//SPI 写1个字节
//TxData:要写入的字节
//返回值:读取到的字节
HAL_StatusTypeDef USR_SPI_WriteByte(SPI_PORT_E ucPORT,uint8_t TxData)
{
	HAL_StatusTypeDef status = HAL_ERROR;

	if(ucPORT == USR_SPI1)
		status = HAL_SPI_Transmit(&SPI1_Handler,&TxData,1, 1000);
	else if(ucPORT == USR_SPI5)
		status = HAL_SPI_Transmit(&SPI5_Handler,&TxData,1, 1000);
 	return status;          		    //返回收到的数据
}

void BackupSRAM_Init(void)
{ 
    /* 电源接口时钟使能 (Power interface clock enable) */
	__HAL_RCC_PWR_CLK_ENABLE();
    /* DBP 位置 1，使能对备份域的访问 */
	HAL_PWR_EnableBkUpAccess();
    /* 通过将 RCC AHB1 外设时钟使能寄存器 (RCC_AHB1ENR) 中的 BKPSRAMEN 位置 1， 使能备份 SRAM 时钟 */
	__HAL_RCC_BKPSRAM_CLK_ENABLE();
    /* 应用程序必须等待备份调压器就绪标志 (BRR) 置 1，指示在待机模式和 VBAT 模式下会保持写入 RAM 中的数据。 */
	HAL_PWREx_EnableBkUpReg();
	//RCC->APB1ENR|=1<<28;					//使能电源接口时钟
	//PWR->CR|=1<<8;							//后备区域访问使能(RTC+SRAM)
	//SYS_DeviceClockEnable(DEV_BKP,TRUE);	//备份区SRAM使能
	//RCC->AHB1LPENR |= 1<<18;				//睡眠模式期间的备份 SRAM 接口时钟使能
	//PWR->CSR |= 1<<9;						//使能备份调压器,不开启会导致备份SRAM掉电丢失-必须先使能时钟
	//return TRUE;
}

uint16_t BackupSRAM_WriteData(uint8_t *pData, uint16_t AddrOffset, uint16_t DataLen)
{ 

	uint32_t len;

	if(pData==NULL) return 0;											//无效的地址
	if(DataLen==0) return 0;											//无效的数量
	if(AddrOffset >= BACKUP_SRAM_SIZE) return 0;						//起始地址有误
	len = AddrOffset + DataLen;	
	if(len > BACKUP_SRAM_SIZE) len = BACKUP_SRAM_SIZE;					//限制范围，只有4KB
	len -= AddrOffset;													//计算要写入的数据长度
	memcpy((uint8_t *)BKPSRAM_BASE+AddrOffset, pData, DataLen);

    return len;
}

uint16_t BackupSRAM_ReadData(uint8_t *pData, uint16_t AddrOffset, uint16_t DataLen)
{ 

	uint32_t len;

	if(pData==NULL) return 0;											//无效的地址
	if(DataLen==0) return 0;											//无效的数量
	if(AddrOffset >= BACKUP_SRAM_SIZE) return 0;						//起始地址有误
	len = AddrOffset + DataLen;	
	if(len > BACKUP_SRAM_SIZE) len = BACKUP_SRAM_SIZE;					//限制范围，只有4KB
	len -= AddrOffset;													//计算要写入的数据长度
	memcpy(pData, (uint8_t *)BKPSRAM_BASE+AddrOffset, DataLen);

	return len;
}
